#include "stdafx.h"

#include "tile.h"
#include "iostream"

#define USE_BICUBIC_INTERPOLATION 1

// should I draw black borders around every tile?
#define USE_TILE_BORDERS 1

namespace Demo {

Tile::Tile()
    :_texture(GLC::Texture2DRef::createNull())
{
    for (int i=0;i!= 4;i++)
    {
        for (int j=0;j!=4;j++)
        {
            _edges_h[i][j] = 0;
        }
    }
}

Tile::~Tile()
{
}

void Tile::setHeight(float h,int x,int y)
{
    if (x >=0 && x < 4)
    {
        if (y >=0 && y < 4)
        {
            _edges_h[x][y] = h;
        }
    }
}

void Tile::renderQuadByLines()const
{
    double step = 0.1;

    glColor3f(1,0,0);
    glBegin(GL_LINE_STRIP);
    for (int i=0;i != 10;i++)
    {
        for (int j=0;j <= 10;j++)
        {
            double x1,x2,y,h1,h2;
            x1 = step*i;
            x2 = step*(i+1);
            y =  step*j;

            h1 = f(x1,y);
            h2 = f(x2,y);

            glVertex3d(x1,y,h1);
            glVertex3d(x2,y,h2);
        }

    }
    glEnd();
}

double Tile::f(double x, double y)const
{
    double res;

    if (!USE_BICUBIC_INTERPOLATION)
    {
        res = _edges_h[1][1]*(1-x)*(1-y) + _edges_h[2][1]*x*(1-y) + _edges_h[1][2]*(1-x)*y + _edges_h[2][2]*x*y;
    }
    else
    {
        res = bicubic(x,y);
    }
    return res;
}

double interpol(double y0,double y1,double y2,double y3, double arg)
{
    double res;
    int N = 4;
    double x[4] = {-1, 0, 1, 2};
    double y[4] = {y0, y1, y2,  y3};

    gsl_interp_accel *acc = gsl_interp_accel_alloc ();
    const gsl_interp_type *t = gsl_interp_cspline_periodic;
    gsl_spline *spline = gsl_spline_alloc (t, N);

    gsl_spline_init (spline, x, y, N);
    res = gsl_spline_eval (spline, arg, acc);
    gsl_spline_free (spline);
    gsl_interp_accel_free (acc);

    return res;
}

double Tile::bicubic(double x,double y)const
{

    double res, h1,h2,h3,h4;
    h1 = interpol(_edges_h[0][0],_edges_h[0][1],_edges_h[0][2],_edges_h[0][3],y);
    h2 = interpol(_edges_h[1][0],_edges_h[1][1],_edges_h[1][2],_edges_h[1][3],y);
    h3 = interpol(_edges_h[2][0],_edges_h[2][1],_edges_h[2][2],_edges_h[2][3],y);
    h4 = interpol(_edges_h[3][0],_edges_h[3][1],_edges_h[3][2],_edges_h[3][3],y);
    res = interpol(h1,h2,h3,h4,x);
    return res;
}

void Tile::render() const
{
    ground().bind();
    renderQuadByLines();
    for (auto item = entities().begin(); item != entities().end(); ++item)
    {
        (*item)->render();
    }
}

const EntityContainer &Tile::entities() const
{
    return _entities;
}

EntityContainer &Tile::entities()
{
    return _entities;
}

bool Tile::hasObstacle()
{
    return (entities().begin() != entities().end());
}

GLC::Texture2DRef Tile::ground() const
{
    return _texture;
}

void Tile::setGround(const GLC::Texture2DRef &texture)
{
    _texture = texture;
}

} // namespace Demo
